package com.lock.chess.controller;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.lock.chess.Enums.MessageEnum;
import com.lock.chess.dto.*;
import com.lock.chess.service.GameService;
import com.lock.chess.service.PlayerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Title: WebSocketServer
 * @Package: com.jiayuan.common.config
 * @Description: websocket的服务端
 * @Author: xmc
 * @Date: 创建时间 2024-04-24
 */
@Component
@Slf4j
@ServerEndpoint("/data")
public class WebSocketServer implements ApplicationContextAware {
    GameService gameService;
    PlayerService playerService;
    private static ApplicationContext applicationContext;

    public static boolean isPlayerAlive(String otherPlayer) {
        return StringUtils.isNotBlank(otherPlayer) && webSocketMap.containsKey(otherPlayer);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        WebSocketServer.applicationContext = applicationContext;
    }

    /**
     * 静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的WebSocket对象。
     */
    private static ConcurrentHashMap<String, Session> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 连接建立成
     * 功调用的方法
     */
    @OnOpen
    public void onOpen() {
         gameService = applicationContext.getBean(GameService.class);
         playerService = applicationContext.getBean(PlayerService.class);
    }

    public static void addWebSocketMap(Session session, String userCode){
        if (webSocketMap.containsKey(userCode)) {
            try {
                if(!webSocketMap.get(userCode).getId().equals(session.getId())) {
                    webSocketMap.get(userCode).close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            //加入set中
            webSocketMap.put(userCode, session);
        } else {
            //加入set中
            webSocketMap.put(userCode, session);
        }
        log.info("用户连接:" + userCode );
    }

    /**
     * 连接关闭
     * 调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        System.out.println(session);
        //通过session找到key
        for (Map.Entry<String, Session> entry : webSocketMap.entrySet()) {
            if (entry.getValue().getId().equals(session.getId())) {
                gameService.cancelGame(session, entry.getKey());
                break;
            }
        }
        webSocketMap.values().removeIf(session::equals);
        log.info("有人下线");
    }

    /**
     * 收到客户端消
     * 息后调用的方法
     *
     * @param message 客户端发送过来的消息
     **/
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("报文:" + message);

        //可以群发消息
        //消息保存到数据库、redis
        if (StringUtils.isNotBlank(message)) {
            try {
                //解析发送的报文
                JSONObject jsonObject = JSONUtil.parseObj(message);
                String type = jsonObject.getStr("type");
                if(StringUtils.isNotBlank(jsonObject.getStr("userCode"))){
                    addWebSocketMap(session, jsonObject.getStr("userCode"));
                }
                if (MessageEnum.REGISTER.getCode().equals(type)) {
                    playerService.createPlayer(session, jsonObject.toBean(PlayerDto.class));
                } else if (MessageEnum.LOGIN.getCode().equals(type)) {
                    //userCode登录
                    playerService.playerLogin(session, jsonObject.getStr("userCode"));
                } else if (MessageEnum.MATCH.getCode().equals(type)) {
                    gameService.matchGame(session, jsonObject.getStr("userCode"));
                } else if (MessageEnum.CANCEL.getCode().equals(type)){
                    gameService.cancelGame(session, jsonObject.getStr("userCode"));
                } else if (MessageEnum.MOVE.getCode().equals(type)) {
                    gameService.gameMoveAction(session, jsonObject.toBean(GameMoveAction.class), false);
                } else if (MessageEnum.END.getCode().equals(type)) {
                    gameService.gameOverAction(session, jsonObject.toBean(GameOverAction.class));
                } else if (MessageEnum.MOVE_SPECIAL.getCode().equals(type)){
                    gameService.gameMoveAction(session, jsonObject.toBean(GameMoveAction.class), true);
                } else if (MessageEnum.LEVEL_UP.getCode().equals(type)){
                    gameService.levelUp(session, jsonObject.toBean(GameLevelUpAction.class));
                } else if (MessageEnum.STAR_UP.getCode().equals(type)){
                    gameService.starUp(session, jsonObject.toBean(GameStarUpAction.class));
                } else if (MessageEnum.CHAT.getCode().equals(type)){
                    gameService.gameChat(session, jsonObject.toBean(GameChatDto.class));
                }else if(MessageEnum.LOGON.getCode().equals(type)){
                    playerService.logOn(session, jsonObject.toBean(PlayerDto.class));
                }else if(MessageEnum.EAT.getCode().equals(type)){
                    gameService.gameEatAction(session, jsonObject.toBean(GameEatAction.class));
                }else if(MessageEnum.SEND_SMS.getCode().equals(type)){
                    playerService.sendSMS(session, jsonObject.getStr("phone"));
                }else if(MessageEnum.MONEY_UPLOAD.getCode().equals(type)){
                    gameService.uploadMoney(session, jsonObject.getStr("money"), jsonObject.getStr("toUserCode"));
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {

        error.printStackTrace();
    }

    /**
     * 实现服务
     * 器主动推送
     */
    public static void sendMessage(String message, String userCode) throws IOException {
        log.info("发送消息到:" + userCode + "，报文:" + message);
        if (StringUtils.isNotBlank(userCode) && webSocketMap.containsKey(userCode)) {
            webSocketMap.get(userCode).getBasicRemote().sendText(message);
        } else {
            log.error("用户" + userCode + ",不在线！");
        }
    }
    /**
     * 实现服务
     * 器主动推送
     */
    public static void sendMessage(String message, Session session) throws IOException {
        session.getBasicRemote().sendText(message);
    }


}
 
